home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / gnustuff / tos / gnumake / make-3~1.zoo / job.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-11-11  |  34.1 KB  |  1,493 lines

  1. /* Job execution and handling for GNU Make.
  2. Copyright (C) 1988-1991 Free Software Foundation, Inc.
  3. This file is part of GNU Make.
  4.  
  5. GNU Make is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 1, or (at your option)
  8. any later version.
  9.  
  10. GNU Make is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with GNU Make; see the file COPYING.  If not, write to
  17. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. #include "make.h"
  20. #include "commands.h"
  21. #include "job.h"
  22. #include "file.h"
  23. #include "variable.h"
  24. #include <errno.h>
  25.  
  26. /* Default path to search for executables.  */
  27. #ifdef atarist
  28. static char default_path[] = ";/bin";
  29. #else
  30. static char default_path[] = ":/bin:/usr/bin";
  31. #endif
  32.  
  33. /* Default shell to use.  */
  34. char default_shell[] = "/bin/sh";
  35.  
  36. extern int errno;
  37.  
  38. #if    defined(USG) && !defined(HAVE_VFORK)
  39. #define    vfork    fork
  40. #define    VFORK_NAME    "fork"
  41. #else    /* Have vfork or not USG.  */
  42. #define    VFORK_NAME    "vfork"
  43. #endif    /* USG and don't have vfork.  */
  44. extern int vfork ();
  45.  
  46. #ifdef    _POSIX_SOURCE
  47. #include <sys/wait.h>
  48.  
  49. #define    WAIT_NOHANG(status)    waitpid(-1, (status), WNOHANG)
  50.  
  51. #else    /* Not _POSIX_SOURCE.  */
  52.  
  53. #if    defined(HAVE_SYS_WAIT) || !defined(USG)
  54. #include <sys/wait.h>
  55. #include <sys/time.h>
  56. #include <sys/resource.h>
  57.  
  58. #ifndef    wait3
  59. extern int wait3 ();
  60. #endif
  61. #define    WAIT_NOHANG(status)    wait3((status), WNOHANG, (struct rusage *) 0)
  62.  
  63. #ifndef    wait
  64. extern int wait ();
  65. #endif
  66. #endif    /* HAVE_SYS_WAIT || !USG */
  67. #endif    /* _POSIX_SOURCE.  */
  68.  
  69. #if    defined(WTERMSIG) || (defined(USG) && !defined(HAVE_SYS_WAIT))
  70. #define    WAIT_T int
  71.  
  72. #ifndef    WTERMSIG
  73. #define WTERMSIG(x) ((x) & 0x7f)
  74. #endif
  75. #ifndef    WCOREDUMP
  76. #define WCOREDUMP(x) ((x) & 0x80)
  77. #endif
  78. #ifndef    WEXITSTATUS
  79. #define WEXITSTATUS(x) (((x) >> 8) & 0xff)
  80. #endif
  81. #ifndef    WIFSIGNALED
  82. #define WIFSIGNALED(x) (WTERMSIG (x) != 0)
  83. #endif
  84. #ifndef    WIFEXITED
  85. #define WIFEXITED(x) (WTERMSIG (x) == 0)
  86. #endif
  87.  
  88. #else    /* WTERMSIG not defined and have <sys/wait.h> or not USG.  */
  89.  
  90. #ifdef atarist
  91. #  define WAIT_T int
  92. #  define WTERMSIG(x) 0
  93. #  define WCOREDUMP(x) 0
  94. #  define WEXITSTATUS(x)  x
  95. #  define WIFSIGNALED(x) (WTERMSIG (x) != 0)
  96. #  define WIFEXITED(x) (WTERMSIG (x) == 0)
  97. #  undef WAIT_NOHANG
  98. #else
  99. #define WAIT_T union wait
  100. #define WTERMSIG(x)    ((x).w_termsig)
  101. #define WCOREDUMP(x)    ((x).w_coredump)
  102. #define WEXITSTATUS(x)    ((x).w_retcode)
  103. #endif /* atarist */
  104. #ifndef    WIFSIGNALED
  105. #define    WIFSIGNALED(x)    (WTERMSIG(x) != 0)
  106. #endif
  107. #ifndef    WIFEXITED
  108. #define    WIFEXITED(x)    (WTERMSIG(x) == 0)
  109. #endif
  110.  
  111. #endif    /* WTERMSIG defined or USG and don't have <sys/wait.h>.  */
  112.  
  113.  
  114. #if    defined(__GNU_LIBRARY__) || defined(_POSIX_SOURCE)
  115. #include <sys/types.h>
  116. #define    GID_T    gid_t
  117. #ifdef    hpux
  118. #include <sys/param.h>
  119. #define getdtablesize() NOFILE
  120. #endif
  121. #else    /* Not GNU C library.  */
  122.  
  123. #define    GID_T    int
  124.  
  125. extern int dup2 ();
  126. extern int fork (), execve ();
  127. extern void _exit ();
  128. extern int geteuid (), getegid ();
  129. extern int setgid (), getgid ();
  130.  
  131. #ifndef USG
  132. extern int getdtablesize ();
  133. #else
  134. #include <sys/param.h>
  135. #define getdtablesize() NOFILE
  136. #endif
  137. #endif    /* GNU C library.  */
  138.  
  139.  
  140. extern void wait_to_start_job ();
  141. extern int start_remote_job_p ();
  142. extern int start_remote_job (), remote_status ();
  143.  
  144.  
  145. #if    (defined(USG) && !defined(HAVE_SIGLIST)) || defined(DGUX)
  146. static char *sys_siglist[NSIG];
  147. void init_siglist ();
  148. #else    /* Not (USG and HAVE_SIGLIST), or DGUX.  */
  149. extern char *sys_siglist[];
  150. #endif    /* USG and not HAVE_SIGLIST, or DGUX.  */
  151.  
  152. int child_handler ();
  153. static void free_child (), start_job ();
  154.  
  155. /* Chain of all children.  */
  156.  
  157. struct child *children = 0;
  158.  
  159. /* Number of children currently running.  */
  160.  
  161. unsigned int job_slots_used = 0;
  162.  
  163. /* Nonzero if the `good' standard input is in use.  */
  164.  
  165. static int good_stdin_used = 0;
  166.  
  167. /* Write an error message describing the exit status given in
  168.    EXIT_CODE, EXIT_SIG, and COREDUMP, for the target TARGET_NAME.
  169.    Append "(ignored)" if IGNORED is nonzero.  */
  170.  
  171. static void
  172. child_error (target_name, exit_code, exit_sig, coredump, ignored)
  173.      char *target_name;
  174.      int exit_code, exit_sig, coredump;
  175.      int ignored;
  176. {
  177.   char *ignore_string = ignored ? " (ignored)" : "";
  178.  
  179.   if (exit_sig == 0)
  180.     error ("*** [%s] Error %d%s", target_name, exit_code, ignore_string);
  181.   else
  182.     {
  183.       char *coredump_string = coredump ? " (core dumped)" : "";
  184.       if (exit_sig > 0 && exit_sig < NSIG)
  185.     error ("*** [%s] %s%s",
  186.            target_name, sys_siglist[exit_sig], coredump_string);
  187.       else
  188.     error ("*** [%s] Signal %d%s", target_name, exit_sig, coredump_string);
  189.     }
  190. }
  191.  
  192. extern void block_remote_children (), unblock_remote_children ();
  193.  
  194. extern int fatal_signal_mask;
  195.  
  196. #ifdef    USG
  197. /* Set nonzero in the interval when it's possible that we may see a dead
  198.    child that's not in the `children' chain.  */
  199. static int unknown_children_possible = 0;
  200. #endif
  201.  
  202.  
  203. /* Block the child termination signal and fatal signals.  */
  204.  
  205. static void
  206. block_signals ()
  207. {
  208. #ifdef USG
  209.  
  210.   /* Tell child_handler that it might see children that aren't yet
  211.      in the `children' chain.  */
  212.   unknown_children_possible = 1;
  213.  
  214.   /* Ignoring SIGCLD makes wait always return -1.
  215.      Using the default action does the right thing.  */
  216.   (void) SIGNAL (SIGCLD, SIG_DFL);
  217.  
  218. #else    /* Not USG.  */
  219.  
  220.   /* Block the signals.  */
  221. #ifndef atarist
  222.   (void) sigblock (fatal_signal_mask | sigmask (SIGCHLD));
  223. #endif /* atarist */
  224.  
  225. #endif
  226.  
  227.   block_remote_children ();
  228. }
  229.  
  230. /* Unblock the child termination signal and fatal signals.  */
  231. static void
  232. unblock_signals ()
  233. {
  234. #ifdef    USG
  235.  
  236.   (void) SIGNAL (SIGCLD, child_handler);
  237.  
  238.   /* It should no longer be possible for children not in the chain to die.  */
  239.   unknown_children_possible = 0;
  240.  
  241. #else    /* Not USG.  */
  242.  
  243.   /* Unblock the signals.  */
  244. #ifndef atarist
  245.   (void) sigsetmask (sigblock (0) & ~(fatal_signal_mask | sigmask (SIGCHLD)));
  246. #endif
  247.  
  248. #endif
  249.  
  250.   unblock_remote_children ();
  251. }
  252.  
  253. static char *signals_blocked_p_stack = 0;
  254. static unsigned int signals_blocked_p_max;
  255. static unsigned int signals_blocked_p_depth;
  256.  
  257. /* Make signals blocked in FLAG is nonzero, unblocked if FLAG is zero.
  258.    Push this setting on the signals_blocked_p_stack, so it can be
  259.    popped off by pop_signals_blocked_p.  */
  260.  
  261. void
  262. push_signals_blocked_p (flag)
  263.      int flag;
  264. {
  265.   int blocked;
  266.  
  267.   if (signals_blocked_p_stack == 0)
  268.     {
  269.       signals_blocked_p_max = 8;
  270.       signals_blocked_p_stack = (char *) xmalloc (8);
  271.       signals_blocked_p_depth = 1;
  272.       signals_blocked_p_stack[0] = flag;
  273.  
  274.       blocked = 0;
  275.     }
  276.   else
  277.     {
  278.       if (signals_blocked_p_depth == signals_blocked_p_max)
  279.     {
  280.       signals_blocked_p_max += 8;
  281.       signals_blocked_p_stack
  282.         = (char *) xrealloc(signals_blocked_p_stack,
  283.                 signals_blocked_p_max);
  284.     }
  285.  
  286.       blocked = (signals_blocked_p_depth > 0
  287.          && signals_blocked_p_stack[signals_blocked_p_depth - 1]);
  288.  
  289.       signals_blocked_p_stack[++signals_blocked_p_depth - 1] = flag;
  290.     }
  291.  
  292.   if (blocked && !flag)
  293.     unblock_signals ();
  294.   else if (flag && !blocked)
  295.     block_signals ();
  296. }
  297.  
  298. /* Pop the signals_blocked_p setting from the stack
  299.    and block or unblock signals as appropriate.  */
  300.  
  301. void
  302. pop_signals_blocked_p ()
  303. {
  304.   int blocked, block;
  305.  
  306.   blocked = (signals_blocked_p_depth > 0
  307.          && signals_blocked_p_stack[signals_blocked_p_depth-- - 1]);
  308.  
  309.   block = (signals_blocked_p_depth > 0
  310.        && signals_blocked_p_stack[signals_blocked_p_depth - 1]);
  311.  
  312.   if (block && !blocked)
  313.     block_signals ();
  314.   else if (blocked && !block)
  315.     unblock_signals ();
  316. }
  317.  
  318. extern int shell_function_pid, shell_function_completed;
  319.  
  320. /* Handle a child-termination signal (SIGCHLD, or SIGCLD for USG),
  321.    storing the returned status and the new command state (`cs_finished')
  322.    in the `file' member of the `struct child' for the dead child,
  323.    and removing the child from the chain.
  324.  
  325.    If we were called as a signal handler, SIG should be SIGCHLD
  326.    (SIGCLD for USG).  If instead it is zero, we were called explicitly
  327.    and should block waiting for running children.
  328.    If SIG is < 0, - SIG is the maximum number of children to bury (record
  329.    status of and remove from the chain).  */
  330.  
  331. int
  332. child_handler (sig)
  333.      int sig;
  334. {
  335.   WAIT_T status;
  336.   unsigned int dead_children = 0;
  337.  
  338.   if (sig > 0)
  339.     block_signals ();
  340.  
  341.   while (1)
  342.     {
  343.       int remote = 0;
  344.       register int pid;
  345.       int exit_code, exit_sig, coredump;
  346.       register struct child *lastc, *c;
  347.       int child_failed;
  348.  
  349.       /* First, check for remote children.  */
  350.       pid = remote_status (&exit_code, &exit_sig, &coredump, 0);
  351.       if (pid < 0)
  352.     {
  353.       /* No remote children.  Check for local children.  */
  354.  
  355. #ifdef    WAIT_NOHANG
  356.       if (sig > 0)
  357.         pid = WAIT_NOHANG (&status);
  358.       else
  359.         pid = wait (&status);
  360. #else    /* USG and don't HAVE_SYS_WAIT.  */
  361.       /* System V cannot do non-blocking waits, so we have two
  362.          choices if called as a signal handler: handle only one
  363.          child (there may be more if the signal was blocked),
  364.          or block waiting for more.  The latter option makes
  365.          parallelism useless, so we must choose the former.  */
  366.       pid = wait (&status);
  367. #endif    /* HAVE_SYS_WAIT or not USG.  */
  368.  
  369.       if (pid <= 0)
  370.         /* No local children.  */
  371.         break;
  372.       else
  373.         {
  374.           /* Chop the status word up.  */
  375.           exit_code = WEXITSTATUS (status);
  376.           exit_sig = WIFSIGNALED (status) ? WTERMSIG (status) : 0;
  377.           coredump = WCOREDUMP (status);
  378.         }
  379.     }
  380.       else
  381.     /* We got a remote child.  */
  382.     remote = 1;
  383.  
  384.       /* Check if this is the child of the `shell' function.  */
  385.       if (!remote && pid == shell_function_pid)
  386.     {
  387.       /* It is.  Leave an indicator for the `shell' function.  */
  388.       if (exit_sig == 0 && exit_code == 127)
  389.         shell_function_completed = -1;
  390.       else
  391.         shell_function_completed = 1;
  392.  
  393.       /* Check if we have reached our quota of children.  */
  394.       ++dead_children;
  395.       if (sig < 0 && dead_children == -sig)
  396.         break;
  397. #if    defined(USG) && !defined(HAVE_SYS_WAIT)
  398.       else if (sig > 0)
  399.         break;
  400. #endif
  401.       else
  402.         continue;
  403.     }
  404.  
  405.       child_failed = exit_sig != 0 || exit_code != 0;
  406.  
  407.       /* Search for a child matching the deceased one.  */
  408.       lastc = 0;
  409.       for (c = children; c != 0; lastc = c, c = c->next)
  410.     if (c->remote == remote && c->pid == pid)
  411.       break;
  412.  
  413.       if (c == 0)
  414.     {
  415.       /* An unknown child died.  */
  416. #ifdef    USG
  417.       if (!unknown_children_possible)
  418.         {
  419. #endif
  420.           char buf[100];
  421.           sprintf (buf, "Unknown%s job %d", remote ? " remote" : "", pid);
  422.           if (child_failed)
  423.         child_error (buf, exit_code, exit_sig, coredump,
  424.                  ignore_errors_flag);
  425.           else
  426.         error ("%s finished.", buf);
  427. #ifdef    USG
  428.         }
  429. #endif
  430.     }
  431.       else
  432.     {
  433.       /* If this child had the good stdin, say it is now free.  */
  434.       if (c->good_stdin)
  435.         good_stdin_used = 0;
  436.  
  437.       if (child_failed && !c->noerror && !ignore_errors_flag)
  438.         {
  439.           /* The commands failed.  Write an error message,
  440.          delete non-precious targets, and abort.  */
  441.           child_error (c->file->name, exit_code, exit_sig, coredump, 0);
  442.           c->file->update_status = 1;
  443.           if (exit_sig != 0)
  444.         delete_child_targets (c);
  445.         }
  446.       else
  447.         {
  448.           if (child_failed)
  449.         {
  450.           /* The commands failed, but we don't care.  */
  451.           child_error (c->file->name,
  452.                    exit_code, exit_sig, coredump, 1);
  453.           child_failed = 0;
  454.         }
  455.  
  456.           /* If there are more commands to run, try to start them.  */
  457.           start_job (c);
  458.  
  459.           switch (c->file->command_state)
  460.         {
  461.         case cs_running:
  462.           /* Successfully started.  Loop to reap more children.  */
  463.           continue;
  464.  
  465.         case cs_finished:
  466.           if (c->file->update_status != 0)
  467.             {
  468.               /* We failed to start the commands.  */
  469.               delete_child_targets (c);
  470.             }
  471.           break;
  472.  
  473.         default:
  474.           error ("internal error: `%s' command_state \
  475. %d in child_handler", c->file->name);
  476.           abort ();
  477.           break;
  478.         }
  479.         }
  480.  
  481.       /* Set the state flag to say the commands have finished.  */
  482.       c->file->command_state = cs_finished;
  483.       notice_finished_file (c->file);
  484.  
  485.       /* Remove the child from the chain and free it.  */
  486.       if (lastc == 0)
  487.         children = c->next;
  488.       else
  489.         lastc->next = c->next;
  490.       free_child (c);
  491.  
  492.       /* There is now another slot open.  */
  493.       --job_slots_used;
  494.  
  495.       /* If the job failed, and the -k flag was not given, die.  */
  496.       if (child_failed && !keep_going_flag)
  497.         die (1);
  498.  
  499.       /* See if we have reached our quota for blocking.  */
  500.       ++dead_children;
  501.       if (sig < 0 && dead_children == -sig)
  502.         break;
  503. #if    defined(USG) && !defined(HAVE_SYS_WAIT)
  504.       else if (sig > 0)
  505.         break;
  506. #endif
  507.     }
  508.     }
  509.  
  510. #ifdef    USG
  511.   if (sig > 0)
  512.     (void) SIGNAL (sig, child_handler);
  513. #endif
  514.  
  515.   if (sig > 0)
  516.     unblock_signals ();
  517.  
  518.   return 0;
  519. }
  520.  
  521.  
  522. /* Wait for N children, blocking if necessary.
  523.    If N is zero, wait until we run out of children.
  524.    If ERR is nonzero and we have any children to wait for,
  525.    print a message on stderr.  */
  526.  
  527. void
  528. wait_for_children (n, err)
  529.      unsigned int n;
  530.      int err;
  531. {
  532.   push_signals_blocked_p (1);
  533.  
  534.   if (err && (children != 0 || shell_function_pid != 0))
  535.     {
  536.       fflush (stdout);
  537.       error ("*** Waiting for unfinished jobs....");
  538.     }
  539.  
  540.   /* Call child_handler to do the work.  */
  541.   (void) child_handler (- (int) n);
  542.  
  543.   pop_signals_blocked_p ();
  544. }
  545.  
  546. /* Free the storage allocated for CHILD.  */
  547.  
  548. static void
  549. free_child (child)
  550.      register struct child *child;
  551. {
  552.   if (child->command_lines != 0)
  553.     {
  554.       register unsigned int i;
  555.       for (i = 0; i < child->file->cmds->ncommand_lines; ++i)
  556.     free (child->command_lines[i]);
  557.       free ((char *) child->command_lines);
  558.     }
  559.  
  560.   if (child->environment != 0)
  561.     {
  562.       register char **ep = child->environment;
  563.       while (*ep != 0)
  564.     free (*ep++);
  565.       free ((char *) child->environment);
  566.     }
  567.  
  568.   free ((char *) child);
  569. }
  570.  
  571. /* Start a job to run the commands specified in CHILD.
  572.    CHILD is updated to reflect the commands and ID of the child process.  */
  573.  
  574. static void
  575. start_job (child)
  576.      register struct child *child;
  577. {
  578.   static int bad_stdin = -1;
  579.   char *end;
  580.   register char *p;
  581.   int backslash;
  582.   char noprint = 0, recursive;
  583.   char **argv;
  584.  
  585.   /* Set RECURSIVE if the unexpanded line contains $(MAKE).  */
  586.   recursive = child->file->cmds->lines_recurse[child->command_line];
  587.  
  588.   if (child->command_ptr == 0 || *child->command_ptr == '\0')
  589.     {
  590.       /* There are no more lines in the expansion of this line.  */
  591.       if (child->command_line == child->file->cmds->ncommand_lines)
  592.     {
  593.       /* There are no more lines to be expanded.  */
  594.       child->command_ptr = 0;
  595.       child->file->command_state = cs_finished;
  596.       child->file->update_status = 0;
  597.       return;
  598.     }
  599.       else
  600.     /* Get the next line to run.  */
  601.     child->command_ptr = child->command_lines[child->command_line++];
  602.     }
  603.  
  604.   /* Find the end of this line.  Backslash-newlines don't mean the end.  */
  605.  
  606.   end = child->command_ptr;
  607.   while (*end != '\0')
  608.     {
  609.       p = index (end, '\n');
  610.       if (p == 0)
  611.     {
  612.       end += strlen (end);
  613.       break;
  614.     }
  615.  
  616.       end = p;
  617.       backslash = 0;
  618.       while (*--p == '\\')
  619.     backslash = !backslash;
  620.  
  621.       if (backslash)
  622.     {
  623.       ++end;
  624.       /* If there is a tab after a backslash-newline,
  625.          remove it, since it was most likely used to line
  626.          up the continued line with the previous one.  */
  627.       if (*end == '\t')
  628.         strcpy (end, end + 1);
  629.     }
  630.       else
  631.     break;
  632.     }
  633.  
  634.   p = child->command_ptr;
  635.  
  636.   if (*end == '\0')
  637.     child->command_ptr = 0;
  638.   else
  639.     {
  640.       *end = '\0';
  641.       child->command_ptr = end + 1;
  642.     }
  643.  
  644.   child->noerror = 0;
  645.   while (*p != '\0')
  646.     {
  647.       if (*p == '@')
  648.     noprint = 1;
  649.       else if (*p == '-')
  650.     child->noerror = 1;
  651.       else if (*p == '+')
  652.     recursive = 1;
  653.       else if (*p != ' ' && *p != '\t')
  654.     break;
  655.       ++p;
  656.     }
  657.  
  658.   /* If -q was given, just say that updating `failed'.  */
  659.   if (question_flag && !recursive)
  660.     goto error;
  661.  
  662.   /* There may be some preceding whitespace left if there
  663.      was nothing but a backslash on the first line.  */
  664.   p = next_token (p);
  665.  
  666.   if (*p == '\0')
  667.     {
  668.       /* There were no commands on this line.  Go to the next.  */
  669.       start_job (child);
  670.       return;
  671.     }
  672.  
  673.   /* Print out the command.  */
  674.  
  675.   if (just_print_flag || (!noprint && !silent_flag))
  676.     puts (p);
  677.  
  678.   /* If -n was given, recurse to get the next line in the sequence.  */
  679.  
  680.   if (just_print_flag && !recursive)
  681.     {
  682.       start_job (child);
  683.       return;
  684.     }
  685.  
  686.   /* Collapse backslash-newlines in this line.  */
  687.  
  688.   collapse_continuations (p);
  689.  
  690.   /* Figure out an argument list from this command line.  */
  691.  
  692.   argv = construct_command_argv (p, child->file);
  693.  
  694.   if (argv == 0)
  695.     {
  696.       /* This line has no commands.  Go to the next.  */
  697.       start_job (child);
  698.       return;
  699.     }
  700.  
  701.   /* Flush the output streams so they won't have things written twice.  */
  702.  
  703.   fflush (stdout);
  704.   fflush (stderr);
  705.   
  706.   /* Set up a bad standard input that reads from a broken pipe.  */
  707.  
  708. #ifndef atarist
  709.   if (bad_stdin == -1)
  710.     {
  711.       /* Make a file descriptor that is the read end of a broken pipe.
  712.      This will be used for some children's standard inputs.  */
  713.       int pd[2];
  714.       if (pipe (pd) == 0)
  715.     {
  716.       /* Close the write side.  */
  717.       (void) close (pd[1]);
  718.       /* Save the read side.  */
  719.       bad_stdin = pd[0];
  720.     }
  721.     }
  722. #endif
  723.  
  724.   /* Decide whether to give this child the `good' standard input
  725.      (one that points to the terminal or whatever), or the `bad' one
  726.      that points to the read side of a broken pipe.  */
  727.  
  728.   child->good_stdin = !good_stdin_used;
  729.   if (child->good_stdin)
  730.     good_stdin_used = 1;
  731.  
  732.   child->deleted = 0;
  733.  
  734.   /* Set up the environment for the child.  */
  735.   if (child->environment == 0)
  736.     child->environment = target_environment (child->file);
  737.  
  738.   if (start_remote_job_p ())
  739.     {
  740.       int is_remote, id, used_stdin;
  741.       if (start_remote_job (argv, child->good_stdin ? 0 : bad_stdin,
  742.                 &is_remote, &id, &used_stdin))
  743.     goto error;
  744.       else
  745.     {
  746.       if (child->good_stdin && !used_stdin)
  747.         {
  748.           child->good_stdin = 0;
  749.           good_stdin_used = 0;
  750.         }
  751.       child->remote = is_remote;
  752.       child->pid = id;
  753.     }
  754.     }
  755.   else
  756.     {
  757.       if (child->command_line - 1 == 0)
  758.     {
  759.       /* Wait for the load to be low enough if this
  760.          is the first command in the sequence.  */
  761.       make_access ();
  762.       wait_to_start_job ();
  763.       user_access ();
  764.     }
  765.  
  766.       /* Fork the child process.  */
  767.  
  768.       child->remote = 0;
  769.       child->pid = vfork ();
  770.       if (child->pid == 0)
  771.     /* We are the child side.  */
  772.     child_execute_job (child->good_stdin ? 0 : bad_stdin, 1,
  773.                argv, child->environment);
  774.       else if (child->pid < 0)
  775.     {
  776.       /* Fork failed!  */
  777.       perror_with_name (VFORK_NAME, "");
  778.       goto error;
  779.     }
  780.     }
  781.  
  782.   /* We are the parent side.  Set the state to
  783.      say the commands are running and return.  */
  784.  
  785.   child->file->command_state = cs_running;
  786.  
  787.   /* Free the storage used by the child's argument list.  */
  788.  
  789.   free (argv[0]);
  790.   free ((char *) argv);
  791.  
  792.   return;
  793.  
  794.  error:;
  795.   child->file->update_status = 1;
  796.   child->file->command_state = cs_finished;
  797. }
  798.  
  799.  
  800. /* Create a `struct child' for FILE and start its commands running.  */
  801.  
  802. void
  803. new_job (file)
  804.      register struct file *file;
  805. {
  806.   register struct commands *cmds = file->cmds;
  807.   register struct child *c;
  808.   char **lines;
  809.   register unsigned int i;
  810.  
  811.   /* Chop the commands up into lines if they aren't already.  */
  812.   chop_commands (cmds);
  813.  
  814.   if (job_slots > 0)
  815.     /* Wait for a job slot to be freed up.  */
  816.     while (job_slots_used == job_slots)
  817.       wait_for_children (1, 0);
  818.  
  819.   /* Expand the command lines and store the results in LINES.  */
  820.   lines = (char **) xmalloc (cmds->ncommand_lines * sizeof (char *));
  821.   for (i = 0; i < cmds->ncommand_lines; ++i)
  822.     lines[i] = allocated_variable_expand_for_file (cmds->command_lines[i],
  823.                            file);
  824.  
  825.   /* Start the command sequence, record it in a new
  826.      `struct child', and add that to the chain.  */
  827.  
  828.   push_signals_blocked_p (1);
  829.  
  830.   c = (struct child *) xmalloc (sizeof (struct child));
  831.   c->file = file;
  832.   c->command_lines = lines;
  833.   c->command_line = 0;
  834.   c->command_ptr = 0;
  835.   c->environment = 0;
  836.   start_job (c);
  837.   switch (file->command_state)
  838.     {
  839.     case cs_running:
  840.       c->next = children;
  841.       children = c;
  842.       /* One more job slot is in use.  */
  843.       ++job_slots_used;
  844.       break;
  845.  
  846.     case cs_finished:
  847.       free_child (c);
  848.       notice_finished_file (file);
  849.       break;
  850.  
  851.     default:
  852.       error ("internal error: `%s' command_state == %d in new_job",
  853.          file->name, (int) file->command_state);
  854.       abort ();
  855.       break;
  856.     }
  857.  
  858.   pop_signals_blocked_p ();
  859.  
  860.   if (job_slots == 1 && file->command_state == cs_running)
  861.     {
  862.       /* Since there is only one job slot, make things run linearly.
  863.      Wait for the child to finish, setting the state to `cs_finished'.  */
  864.       while (file->command_state != cs_finished)
  865.     wait_for_children (1, 0);
  866.     }
  867. }
  868.  
  869. /* Replace the current process with one executing the command in ARGV.
  870.    STDIN_FD and STDOUT_FD are used as the process's stdin and stdout; ENVP is
  871.    the environment of the new program.  This function does not return.  */
  872.  
  873. void
  874. child_execute_job (stdin_fd, stdout_fd, argv, envp)
  875.      int stdin_fd, stdout_fd;
  876.      char **argv, **envp;
  877. {
  878.   if (stdin_fd != 0)
  879.     (void) dup2 (stdin_fd, 0);
  880.   if (stdout_fd != 1)
  881.     (void) dup2 (stdout_fd, 1);
  882.  
  883. #ifndef atarist
  884.   /* Free up file descriptors.  */
  885.   {
  886.     register int d;
  887.     int max = getdtablesize ();
  888.     for (d = 3; d < max; ++d)
  889.       (void) close (d);
  890.   }
  891. #endif /* atarist */
  892.  
  893.   /* Don't block signals for the new process.  */
  894.   unblock_signals ();
  895.  
  896.   /* Run the command.  */
  897.   exec_command (argv, envp);
  898. }
  899.  
  900. /* Search PATH for FILE.
  901.    If successful, store the full pathname in PROGRAM and return 1.
  902.    If not sucessful, return zero.  */
  903.  
  904. static int
  905. search_path (file, path, program)
  906.      char *file, *path, *program;
  907. {
  908.   if (path == 0 || path[0] == '\0')
  909.     path = default_path;
  910.  
  911.   if (index (file, '/') != 0)
  912.     {
  913.       strcpy (program, file);
  914.       return 1;
  915.     }
  916.   else
  917. #ifdef atarist
  918.   {
  919.       static char  * * _extensions = 0,  * suff;
  920.       char         * p,  * q;
  921.       int            i;
  922.       
  923.       if ( _extensions == 0 )
  924.       {
  925.       if ( ( p == (char*)getenv( "SUFF" ) ) != 0 && *p )
  926.       {
  927.           suff = (char*) xmalloc( strlen( p ) + 1 );
  928.           strcpy( suff, p );
  929.           for ( i = 1, q = suff;  *q;  q++ )
  930.           if ( *q == ',' || *q == ';' )
  931.               i++;
  932.           _extensions = (char**) xmalloc( i * sizeof( char* ) );
  933.           _extensions[0] = suff;
  934.           for ( i = 0, q = suff;  *q;  q++ )
  935.           if ( *q == ',' || *q == ';' )
  936.           {
  937.               *q = '\0';
  938.               _extensions[ ++i ] = q + 1;
  939.           }
  940.           _extensions[ ++i ] = 0;
  941.       }
  942.           else
  943.           {
  944.           _extensions = (char**) xmalloc( 5 * sizeof( char* ) );
  945.           _extensions[0] = "ttp";
  946.           _extensions[1] = "tos";
  947.           _extensions[2] = "prg";
  948.           _extensions[3] = "app";
  949.           _extensions[4] = 0;
  950.       }
  951.       }
  952.       p = (char*) findfile( file, path, _extensions );
  953.       if ( p == NULL )
  954.       return 0;
  955.       else
  956.       {
  957.       strcpy( program, p );
  958.       return 1;
  959.       }
  960.   }
  961. #else
  962.     {
  963.       unsigned int len;
  964.  
  965. #ifndef    USG
  966.       extern int getgroups ();
  967.       static GID_T groups[NGROUPS];
  968.       static int ngroups = -1;
  969.       if (ngroups == -1)
  970.     ngroups = getgroups (NGROUPS, groups);
  971. #endif    /* Not USG.  */
  972.  
  973.       len = strlen (file) + 1;
  974.       do
  975.     {
  976.       struct stat st;
  977.       int perm;
  978.       char *p;
  979.  
  980.       p = index (path, ':');
  981.       if (p == 0)
  982.         p = path + strlen (path);
  983.  
  984.       if (p == path)
  985.         bcopy (file, program, len);
  986.       else
  987.         {
  988.           bcopy (path, program, p - path);
  989.           program[p - path] = '/';
  990.           bcopy (file, program + (p - path) + 1, len);
  991.         }
  992.  
  993.       if (stat (program, &st) == 0
  994.           && S_ISREG (st.st_mode))
  995.         {
  996.           if (st.st_uid == geteuid ())
  997.         perm = (st.st_mode & 0100);
  998.           else if (st.st_gid == getegid ())
  999.         perm = (st.st_mode & 0010);
  1000.           else
  1001.         {
  1002. #ifndef    USG
  1003.           register int i;
  1004.           for (i = 0; i < ngroups; ++i)
  1005.             if (groups[i] == st.st_gid)
  1006.               break;
  1007.           if (i < ngroups)
  1008.             perm = (st.st_mode & 0010);
  1009.           else
  1010. #endif    /* Not USG.  */
  1011.             perm = (st.st_mode & 0001);
  1012.         }
  1013.  
  1014.           if (perm != 0)
  1015.         return 1;
  1016.         }
  1017.  
  1018.       path = p + 1;
  1019.     } while (*path != '\0');
  1020.     }
  1021.  
  1022.   return 0;
  1023. #endif /* atarist */
  1024. }
  1025.  
  1026. /* Replace the current process with one running the command in ARGV,
  1027.    with environment ENVP.  This function does not return.  */
  1028.  
  1029. void
  1030. exec_command (argv, envp)
  1031.      char **argv, **envp;
  1032. {
  1033.   char *shell, *path;
  1034.   char program[MAXPATHLEN];
  1035.   register char **ep;
  1036.  
  1037.   shell = path = 0;
  1038.   for (ep = envp; *ep != 0; ++ep)
  1039.     {
  1040.       if (shell == 0 && !strncmp(*ep, "SHELL=", 6))
  1041.     shell = &(*ep)[6];
  1042.       else if (path == 0 && !strncmp(*ep, "PATH=", 5))
  1043.     path = &(*ep)[5];
  1044.       else if (path != 0 && shell != 0)
  1045.     break;
  1046.     }
  1047.  
  1048.   /* Be the user.  */
  1049.   user_access ();
  1050.  
  1051.   if (!search_path (argv[0], path, program))
  1052.     error ("%s: Command not found", argv[0]);
  1053.   else
  1054.     {
  1055.       /* Run the program.  */
  1056.  
  1057.       execvp (program, argv);
  1058.  
  1059.       if (errno == ENOEXEC)
  1060.     {
  1061.       char shell_program[MAXPATHLEN], *shell_path;
  1062.       if (shell == 0)
  1063.         shell_path = default_shell;
  1064.       else
  1065.         {
  1066.           if (search_path (shell, path, shell_program))
  1067.         shell_path = shell_program;
  1068.           else
  1069.         {
  1070.           shell_path = 0;
  1071.           error ("%s: Shell program not found", shell);
  1072.         }
  1073.         }
  1074.  
  1075.       if (shell_path != 0)
  1076.         {
  1077.           char **new_argv;
  1078.           int argc;
  1079.  
  1080.           argc = 1;
  1081.           while (argv[argc] != 0)
  1082.         ++argc;
  1083.  
  1084.           new_argv = (char **) alloca ((1 + argc + 1) * sizeof (char *));
  1085.           new_argv[0] = shell_path;
  1086.           new_argv[1] = program;
  1087.           while (argc > 0)
  1088.         {
  1089.           new_argv[1 + argc] = argv[argc];
  1090.           --argc;
  1091.         }
  1092.           execvp (shell_path, new_argv, envp);
  1093.           perror_with_name ("execvp: ", shell_path);
  1094.         }
  1095.     }
  1096.       else
  1097.     perror_with_name ("execvp: ", program);
  1098.     }
  1099.  
  1100.   _exit (127);
  1101. }
  1102.  
  1103. /* Figure out the argument list necessary to run LINE as a command.
  1104.    Try to avoid using a shell.  This routine handles only ' quoting.
  1105.    Starting quotes may be escaped with a backslash.  If any of the
  1106.    characters in sh_chars[] is seen, or any of the builtin commands
  1107.    listed in sh_cmds[] is the first word of a line, the shell is used.
  1108.  
  1109.    SHELL is the shell to use, or nil to use the default shell.
  1110.    IFS is the value of $IFS, or nil (meaning the default).  */
  1111.  
  1112. static char **
  1113. construct_command_argv_internal (line, shell, ifs)
  1114.      char *line;
  1115.      char *shell, *ifs;
  1116. {
  1117.   static char sh_chars[] = "#;\"*?[]&|<>(){}=$`";
  1118.   static char *sh_cmds[] = { "cd", "eval", "exec", "exit", "login",
  1119.                  "logout", "set", "umask", "wait", "while", "for",
  1120.                  "case", "if", ":", ".", "break", "continue",
  1121.                  "export", "read", "readonly", "shift", "times",
  1122.                  "trap", "switch", 0 };
  1123.   register int i;
  1124.   register char *p;
  1125.   register char *ap;
  1126.   char *end;
  1127.   int instring;
  1128.   char **new_argv = 0;
  1129.  
  1130.   /* See if it is safe to parse commands internally.  */
  1131.   if (shell != 0 && strcmp (shell, default_shell))
  1132.     goto slow;
  1133.  
  1134.   if (ifs != 0)
  1135.     for (ap = ifs; *ap != '\0'; ++ap)
  1136.       if (*ap != ' ' && *ap != '\t' && *ap != '\n')
  1137.     goto slow;
  1138.  
  1139.   i = strlen (line) + 1;
  1140.  
  1141.   /* More than 1 arg per character is impossible.  */
  1142.   new_argv = (char **) xmalloc (i * sizeof (char *));
  1143.  
  1144.   /* All the args can fit in a buffer as big as LINE is.   */
  1145.   ap = new_argv[0] = (char *) xmalloc (i);
  1146.   end = ap + i;
  1147.  
  1148.   /* I is how many complete arguments have been found.  */
  1149.   i = 0;
  1150.   instring = 0;
  1151.   for (p = line; *p != '\0'; ++p)
  1152.     {
  1153.       if (ap > end)
  1154.     abort ();
  1155.  
  1156.       if (instring)
  1157.     {
  1158.       /* Inside a string, just copy any char except a closing quote.  */
  1159.       if (*p == '\'')
  1160.         instring = 0;
  1161.       else
  1162.         *ap++ = *p;
  1163.     }
  1164.       else if (index (sh_chars, *p) != 0)
  1165.     /* Not inside a string, but it's a special char.  */
  1166.     goto slow;
  1167.       else
  1168.     /* Not a special char.  */
  1169.     switch (*p)
  1170.       {
  1171. #ifdef atarist
  1172.       case '@':
  1173. #else
  1174.       case '\\':
  1175. #endif
  1176.         if (p[1] != '\0' && p[1] != '\n')
  1177.           /* Copy and skip the following char.  */
  1178.           *ap++ = *++p;
  1179.         break;
  1180.  
  1181.       case '\'':
  1182.         instring = 1;
  1183.         break;
  1184.  
  1185.       case '\n':
  1186.       case ' ':
  1187.       case '\t':
  1188.         /* We have the end of an argument.
  1189.            Terminate the text of the argument.  */
  1190.         *ap++ = '\0';
  1191.         new_argv[++i] = ap;
  1192.         /* If this argument is the command name,
  1193.            see if it is a built-in shell command.
  1194.            If so, have the shell handle it.  */
  1195.         if (i == 1)
  1196.           {
  1197.         register int j;
  1198.         for (j = 0; sh_cmds[j] != 0; ++j)
  1199.           if (streq (sh_cmds[j], new_argv[0]))
  1200.             goto slow;
  1201.           }
  1202.  
  1203.         /* Ignore multiple whitespace chars.  */
  1204.         p = next_token (p);
  1205.         /* Next iteration should examine the first nonwhite char.  */
  1206.         --p;
  1207.         break;
  1208.  
  1209.       default:
  1210.         *ap++ = *p;
  1211.         break;
  1212.       }
  1213.     }
  1214.  
  1215.   if (instring)
  1216.     /* Let the shell deal with an unterminated quote.  */
  1217.     goto slow;
  1218.  
  1219.   /* Terminate the last argument and the argument list.  */
  1220.  
  1221.   *ap = '\0';
  1222.   if (new_argv[i][0] != '\0')
  1223.     ++i;
  1224.   new_argv[i] = 0;
  1225.  
  1226.   if (new_argv[0] == 0)
  1227.     /* Line was empty.  */
  1228.     return 0;
  1229.   else
  1230.     return new_argv;
  1231.  
  1232.  slow:;
  1233.   /* We must use the shell.  */
  1234.  
  1235.   if (new_argv != 0)
  1236.     {
  1237.       /* Free the old argument list we were working on.  */
  1238.       free (new_argv[0]);
  1239.       free (new_argv);
  1240.     }
  1241.  
  1242.   if (shell == 0 || !strcmp (shell, default_shell))
  1243.     {
  1244.       /* The shell is the default, or we're in a recursive call to construct
  1245.      the argument list for the real shell.  Construct a simple argument
  1246.      list using the default shell.  */
  1247.       new_argv = (char **) xmalloc (4 * sizeof (char *));
  1248.       new_argv[0] = savestring (default_shell, sizeof (default_shell) - 1);
  1249.       new_argv[1] = "-c";
  1250.       new_argv[2] = savestring (line, strlen (line));
  1251.       new_argv[3] = 0;
  1252.     }
  1253.   else
  1254.     {
  1255.       /* SHELL may be a multi-word command.  Construct a command line
  1256.      "SHELL -c LINE", with all special chars in LINE escaped.
  1257.      Then recurse, expanding this command line to get the final
  1258.      argument list.  */
  1259.  
  1260.       unsigned int shell_len = strlen (shell);
  1261.       static char minus_c[] = " -c ";
  1262.       unsigned int line_len = strlen (line);
  1263.       
  1264.       char *new_line = (char *) alloca (shell_len + (sizeof (minus_c) - 1)
  1265.                     + (line_len * 2) + 1);
  1266.  
  1267.       ap = new_line;
  1268.       bcopy (shell, ap, shell_len);
  1269.       ap += shell_len;
  1270.       bcopy (minus_c, ap, sizeof (minus_c) - 1);
  1271.       ap += sizeof (minus_c) - 1;
  1272.       for (p = line; *p != '\0'; ++p)
  1273.     {
  1274.       if (*p == '\\' || *p == '\''
  1275.           || *p == ' ' || *p == '\t' || *p == '\n'
  1276.           || index (sh_chars, *p) != 0)
  1277. #ifdef atarist
  1278.         *ap++ = '@';
  1279. #else
  1280.         *ap++ = '\\';
  1281. #endif
  1282.       *ap++ = *p;
  1283.     }
  1284.       *ap = '\0';
  1285.  
  1286.       new_argv = construct_command_argv_internal (new_line,
  1287.                           (char *) 0, (char *) 0);
  1288.     }
  1289.  
  1290.   return new_argv;
  1291. }
  1292.  
  1293. /* Figure out the argument list necessary to run LINE as a command.
  1294.    Try to avoid using a shell.  This routine handles only ' quoting.
  1295.    Starting quotes may be escaped with a backslash.  If any of the
  1296.    characters in sh_chars[] is seen, or any of the builtin commands
  1297.    listed in sh_cmds[] is the first word of a line, the shell is used.
  1298.  
  1299.    FILE is the target whose commands these are.  It is used for
  1300.    variable expansion for $(SHELL) and $(IFS).  */
  1301.  
  1302. char **
  1303. construct_command_argv (line, file)
  1304.      char *line;
  1305.      struct file *file;
  1306. {
  1307.   char *shell = allocated_variable_expand_for_file ("$(SHELL)", file);
  1308.   char *ifs = allocated_variable_expand_for_file ("$(IFS)", file);
  1309.   char **argv;
  1310.  
  1311.   argv = construct_command_argv_internal (line, shell, ifs);
  1312.  
  1313.   free (shell);
  1314.   free (ifs);
  1315.  
  1316.   return argv;
  1317. }
  1318.  
  1319. #if    (defined(USG) && !defined(HAVE_SIGLIST)) || defined(DGUX)
  1320. /* Initialize sys_siglist.  */
  1321.  
  1322. void
  1323. init_siglist ()
  1324. {
  1325.   char buf[100];
  1326.   register unsigned int i;
  1327.  
  1328.   for (i = 0; i < NSIG; ++i)
  1329.     switch (i)
  1330.       {
  1331.       default:
  1332.     sprintf (buf, "Signal %u", i);
  1333.     sys_siglist[i] = savestring (buf, strlen (buf));
  1334.     break;
  1335.       case SIGHUP:
  1336.     sys_siglist[i] = "Hangup";
  1337.     break;
  1338.       case SIGINT:
  1339.     sys_siglist[i] = "Interrupt";
  1340.     break;
  1341.       case SIGQUIT:
  1342.     sys_siglist[i] = "Quit";
  1343.     break;
  1344.       case SIGILL:
  1345.     sys_siglist[i] = "Illegal Instruction";
  1346.     break;
  1347.       case SIGTRAP:
  1348.     sys_siglist[i] = "Trace Trap";
  1349.     break;
  1350.       case SIGIOT:
  1351.     sys_siglist[i] = "IOT Trap";
  1352.     break;
  1353. #ifdef    SIGEMT
  1354.       case SIGEMT:
  1355.     sys_siglist[i] = "EMT Trap";
  1356.     break;
  1357. #endif
  1358. #ifdef    SIGDANGER
  1359.       case SIGDANGER:
  1360.     sys_siglist[i] = "Danger signal";
  1361.     break;
  1362. #endif
  1363.       case SIGFPE:
  1364.     sys_siglist[i] = "Floating Point Exception";
  1365.     break;
  1366.       case SIGKILL:
  1367.     sys_siglist[i] = "Killed";
  1368.     break;
  1369.       case SIGBUS:
  1370.     sys_siglist[i] = "Bus Error";
  1371.     break;
  1372.       case SIGSEGV:
  1373.     sys_siglist[i] = "Segmentation fault";
  1374.     break;
  1375.       case SIGSYS:
  1376.     sys_siglist[i] = "Bad Argument to System Call";
  1377.     break;
  1378.       case SIGPIPE:
  1379.     sys_siglist[i] = "Broken Pipe";
  1380.     break;
  1381.       case SIGALRM:
  1382.     sys_siglist[i] = "Alarm Clock";
  1383.     break;
  1384.       case SIGTERM:
  1385.     sys_siglist[i] = "Terminated";
  1386.     break;
  1387. #if    !defined (SIGIO) || SIGUSR1 != SIGIO
  1388.       case SIGUSR1:
  1389.     sys_siglist[i] = "User-defined signal 1";
  1390.     break;
  1391. #endif
  1392. #if    !defined (SIGURG) || SIGUSR2 != SIGURG
  1393.       case SIGUSR2:
  1394.     sys_siglist[i] = "User-defined signal 2";
  1395.     break;
  1396. #endif
  1397. #ifdef    SIGCLD
  1398.       case SIGCLD:
  1399. #endif
  1400. #if    defined(SIGCHLD) && !defined(SIGCLD)
  1401.       case SIGCHLD:
  1402. #endif
  1403.     sys_siglist[i] = "Child Process Exited";
  1404.     break;
  1405. #ifdef    SIGPWR
  1406.       case SIGPWR:
  1407.     sys_siglist[i] = "Power Failure";
  1408.     break;
  1409. #endif
  1410. #ifdef    SIGVTALRM
  1411.       case SIGVTALRM:
  1412.     sys_siglist[i] = "Virtual Timer Alarm";
  1413.     break;
  1414. #endif
  1415. #ifdef    SIGPROF
  1416.       case SIGPROF:
  1417.     sys_siglist[i] = "Profiling Alarm Clock";
  1418.     break;
  1419. #endif
  1420. #ifdef    SIGIO
  1421.       case SIGIO:
  1422.     sys_siglist[i] = "I/O Possible";
  1423.     break;
  1424. #endif
  1425. #ifdef    SIGWINDOW
  1426.       case SIGWINDOW:
  1427.     sys_siglist[i] = "Window System Signal";
  1428.     break;
  1429. #endif
  1430. #ifdef    SIGSTOP
  1431.       case SIGSTOP:
  1432.     sys_siglist[i] = "Stopped (signal)";
  1433.     break;
  1434. #endif
  1435. #ifdef    SIGTSTP
  1436.       case SIGTSTP:
  1437.     sys_siglist[i] = "Stopped";
  1438.     break;
  1439. #endif
  1440. #ifdef    SIGCONT
  1441.       case SIGCONT:
  1442.     sys_siglist[i] = "Continued";
  1443.     break;
  1444. #endif
  1445. #ifdef    SIGTTIN
  1446.       case SIGTTIN:
  1447.     sys_siglist[i] = "Stopped (tty input)";
  1448.     break;
  1449. #endif
  1450. #ifdef    SIGTTOU
  1451.       case SIGTTOU:
  1452.     sys_siglist[i] = "Stopped (tty output)";
  1453.     break;
  1454. #endif
  1455. #ifdef    SIGURG
  1456.       case SIGURG:
  1457.     sys_siglist[i] = "Urgent Condition on Socket";
  1458.     break;
  1459. #endif
  1460. #ifdef    SIGXCPU
  1461.       case SIGXCPU:
  1462.     sys_siglist[i] = "CPU Limit Exceeded";
  1463.     break;
  1464. #endif
  1465. #ifdef    SIGXFSZ
  1466.       case SIGXFSZ:
  1467.     sys_siglist[i] = "File Size Limit Exceeded";
  1468.     break;
  1469. #endif
  1470.       }
  1471. }
  1472. #endif    /* USG and not HAVE_SIGLIST.  */
  1473.  
  1474. #if    defined(USG) && !defined(USGr3) && !defined(HAVE_DUP2)
  1475. int
  1476. dup2 (old, new)
  1477.      int old, new;
  1478. {
  1479.   int fd;
  1480.  
  1481.   (void) close (new);
  1482.   fd = dup (old);
  1483.   if (fd != new)
  1484.     {
  1485.       (void) close (fd);
  1486.       errno = EMFILE;
  1487.       return -1;
  1488.     }
  1489.  
  1490.   return fd;
  1491. }
  1492. #endif    /* USG and not USGr3 and not HAVE_DUP2.  */
  1493.